#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <unistd.h>
#include <ctime>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
using namespace std;
#define PID_QUANTITY 10  // 子进程数量
#define NUMBER_OF_BYTES 4// 子进程一次读取的字节数
#define SEND 10//父进程发送消息的数量

class pipeline // 描述进程池属性
{
public:
  pipeline(int fd, pid_t pid) // 构造函数
      : _fd(fd), _pid(pid)
  {
  }

  int _fd;    // 文件描述符
  pid_t _pid; // 进程pid
};

void reception() // 子进程接收任务
{
  int tmp = 0;
  while (true)
  {
    int i = read(0, &tmp, NUMBER_OF_BYTES); // 从信道里读取

    if (NUMBER_OF_BYTES == i)
    {
      printf("我是子进程%d，我读到的数据是：%d\n", getpid(), tmp);
    }

    if (0 == i)
      break;
  }
}

void Cistern(std::vector<pipeline> *vp) // 创建进程池,输出型参数vector<pipeline> * vp
{
 
 
  std::vector<int> oldfds;

  for (int i = 0; i < PID_QUANTITY; i++)
  {
     int fds[2]; // 0下标表示读端，1下表表示写端    
    pipe(fds); // 建立信道

    pid_t tmp_pid = fork(); // 创建子进程

    if (0 == tmp_pid) // 子进程
    {

      for (auto fd : oldfds) // 关闭子进程多余的写端
      {
        close(fd);
      }

      close(fds[1]); // 关闭子进程写端

      dup2(fds[0], 0); // 本来从键盘读取变为从信道读取，减少传参

      close(fds[0]); //  关闭多余的读端

      reception(); // 接收任务

      exit(0); // 子进程结束
    }

    close(fds[0]);                            // 关闭父进程读端
    vp->push_back(pipeline(fds[1], tmp_pid)); // 向父进程管理的进程池中添加字段，父进程信道的文件描述符，以及子进程的pid

    oldfds.push_back(fds[1]); // 记录子进程的写端，方便下一个进程继承后关闭~
  }
}

void Reclaim(std::vector<pipeline> &vp) // 回收子进程
{

for (auto c : vp)
{
  close(c._fd);
  waitpid(c._pid, nullptr, 0);
}

}



void Send(std::vector<pipeline> &vp) //向子进程发消息
{
  for (int k = 0; k < SEND; k++)         
  {
    int i = rand() % 10;
    int j = rand() % 10;

    write(vp[i]._fd, &j, sizeof(int));

    printf("我是父进程，我向子进程传递的数据是%d\n", j);

    sleep(1);    
  }
}

int main()
{
  srand(time(nullptr) ^ getpid() ^ 1023); // 种一个随机数种子

  std::vector<pipeline> pv; // 创建容器管理进程池

  Cistern(&pv); // 初始化

  Send(pv); // 父进程派发任务

 Reclaim(pv); // 关闭信道和等待子进程

  return 0;
}
